//Copyright (c) 2007, Matthew Newman
//All rights reserved.
//
//Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
//
//* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
//
//* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
//
//* Neither the name of BestSnowman.com nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
//
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Microsoft.Win32;
using System.ComponentModel;
using System.IO;
using System.Linq;
using ProductKeysWin.Code;
using BSCTaskDialog;
using ProductKeyDB;

namespace ProductKeysWin

{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>

    public partial class MainWindow : System.Windows.Window
    {
        Pkmdb db;
        protected IEnumerable<Product> products;

        private string searchText = null;
        private SortDirection nameSort = SortDirection.none;

        public MainWindow()
        {
            if (String.IsNullOrEmpty(Properties.Settings.Default.ConnectionString))
            {
                Properties.Settings.Default.ConnectionString = "Data Source=" + System.Environment.CurrentDirectory + "\\pkmdb.sdf";
                Properties.Settings.Default.Save();
            }
            try
            {
                db = new Pkmdb(Properties.Settings.Default.ConnectionString);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
            InitializeComponent();
            
        }

        protected void WindowOnLoaded(object sender, RoutedEventArgs e)
        {
            if (Properties.Settings.Default.SaveLastSearch && !String.IsNullOrEmpty(Properties.Settings.Default.LastSearch))
            {
                this.txtSearch.Text = Properties.Settings.Default.LastSearch;
                chkSearch.IsChecked = true;
                OnSearch(sender, e);
            }

            nameSort = ParseSortName(Properties.Settings.Default.SortNameDirection);
            OnNameSort(null, e);

            SetView();
        }

        private void SetView()
        {
            if (db == null)
            {
                try
                {
                    db = new Pkmdb(Properties.Settings.Default.ConnectionString);
                }
                catch (Exception e)
                {
                    MessageBox.Show(e.ToString());
                }
            }
            db.ClearSimilarity();
            products = from p in db.Products
                       select p;

            if (searchText != null)
            {
                // This query orders the products by similarity and hides any product that has zero similarity
                products = from p in products
                           orderby p.GetSimilarity(searchText) descending
                           where p.SearchSimilarity > 0
                           select p;
            }
            else
            {
                switch (nameSort)
                {
                    case SortDirection.ascending:
                        products = from k in products
                                   orderby k.Name ascending
                                   select k;
                        break;
                    case SortDirection.descending:
                        products = from k in products
                                   orderby k.Name descending
                                   select k;
                        break;
                    default:
                        break;
                }
            }

            listProdKeys.DataContext = products;
        }

        protected void OnNameSort(object sender, RoutedEventArgs e)
        {
            SortNameNone.IsChecked = false;
            SortNameAsc.IsChecked = false;
            SortNameDsc.IsChecked = false;
            if (sender != null)
            {
                nameSort = ParseSortName(((MenuItem)sender).Header.ToString().ToLower());
            }
            switch (nameSort)
            {
                case SortDirection.none:
                    SortNameNone.IsChecked = true;
                    break;
                case SortDirection.ascending:
                    SortNameAsc.IsChecked = true;
                    break;
                case SortDirection.descending:
                    SortNameDsc.IsChecked = true;
                    break;
            }
            SetView();
            Properties.Settings.Default.SortNameDirection = nameSort.ToString();
            Properties.Settings.Default.Save();
        }

        private SortDirection ParseSortName(string name)
        {

            switch (name)
            {
                case "none":
                    return SortDirection.none;
                case "ascending":
                    return SortDirection.ascending;
                case "descending":
                    return SortDirection.descending;
            }
            return SortDirection.none;
        }

        protected void OnSearch(object sender, RoutedEventArgs e)
        {
            searchText = this.txtSearch.Text.ToLower();
            Properties.Settings.Default.LastSearch = searchText;
            SetView();
            Properties.Settings.Default.Save();
        }

        protected void OnUnSearch(object sender, RoutedEventArgs e)
        {
            searchText = null;
            Properties.Settings.Default.LastSearch = searchText;
            SetView();
            Properties.Settings.Default.Save();
        }

        protected void NewButtonClicked(object sender, RoutedEventArgs e)
        {
            NewDialog newDlg = new NewDialog();
            newDlg.Owner = this;
            newDlg.ShowDialog();

            if (newDlg.NewProduct != null && !String.IsNullOrEmpty(newDlg.NewProduct.Name))
            {
                db.Products.InsertOnSubmit(newDlg.NewProduct);
                db.SubmitChanges();
            }

            SetView();
        }

        protected void EditButtonClicked(object sender, RoutedEventArgs e)
        {
            NewDialog newDlg = new NewDialog();
            newDlg.Owner = this;
            newDlg.OldKey = (Product)listProdKeys.SelectedItem;
            newDlg.ShowDialog();

            if (newDlg.NewProduct != null && !String.IsNullOrEmpty(newDlg.NewProduct.Name))
            {
                foreach (ProductKeyDB.Key code in newDlg.OldKey.Keys)
                {
                    db.Keys.DeleteOnSubmit(code);

                }
                db.SubmitChanges();

                db.Products.DeleteOnSubmit(newDlg.OldKey);
                db.Products.InsertOnSubmit(newDlg.NewProduct);
                db.SubmitChanges();

                SetView();
            }
        }

        protected void DeleteButtonClicked(object sender, RoutedEventArgs e)
        {
            try
            {
                if (BSCTaskDialog.BSCTaskDialog.TaskDialog(this, "Delete Product Key?", "Are you sure you want to delete " + ((Product)listProdKeys.SelectedItem).Name
                    + "?", "This will remote the Product and all Keys permanently", TaskDialogButtons.Yes | TaskDialogButtons.No, 
                    TaskDialogIcon.Warning) == TaskDialogResult.Yes)
                {
                    db.Products.DeleteOnSubmit((Product)listProdKeys.SelectedItem);
                    db.SubmitChanges();

                    SetView();
                }
            }
            catch (Exception ex)
            {
                if (MessageBox.Show("Are you sure you want to delete this product key?", "Delete?", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
                {
                    db.Products.DeleteOnSubmit((Product)listProdKeys.SelectedItem);
                    db.SubmitChanges();

                    SetView();
                }
            }
        }

        protected void FileMenuExitClicked(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        private bool DbHasProduct(Product entity, out Product found)
        {
            try
            {
                Product results = db.Products.Single(p => p.Name == entity.Name);
                found = results;
                return true;
            }
            catch (Exception)
            {
                found = null;
                return false;
            }
        }

        private bool ProdHasKey(Product prod, ProductKeyDB.Key key)
        {
            try
            {
                ProductKeyDB.Key results = prod.Keys.Single(k => k.KeyCode == key.KeyCode && k.AllocatedTo == key.AllocatedTo);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        private void MergeKeys(IEnumerable<Product> importkeys)
        {
            foreach (Product prod in importkeys)
            {
                Product found;
                if (DbHasProduct(prod, out found))
                {
                    foreach (ProductKeyDB.Key key in prod.Keys)
                    {
                        if (!ProdHasKey(found, key))
                        {
                            found.Keys.Add(new ProductKeyDB.Key { KeyCode = key.KeyCode, AllocatedTo = key.AllocatedTo });
                        }
                    }
                }
                else
                {
                    db.Products.InsertOnSubmit(prod);
                }
            }
            db.SubmitChanges();
        }

        protected void FileMenuImportPkmXmlClicked(object sender, RoutedEventArgs e)
        {
            OpenFileDialog opendlg = new OpenFileDialog();
            opendlg.DefaultExt = "xml";
            opendlg.Filter = "Xml files (*.xml)|*.xml";
            if ((bool)opendlg.ShowDialog())
            {
                Mouse.OverrideCursor = Cursors.Wait;
                MergeKeys(Code.XmlHandler.ImportPkmXml(new Uri(opendlg.FileName)));
            }
            SetView();
            Mouse.OverrideCursor = Cursors.Arrow;
        }

        protected void FileMenuImportMsdnXmlClicked(object sender, RoutedEventArgs e)
        {
            OpenFileDialog opendlg = new OpenFileDialog();
            opendlg.DefaultExt = "xml";
            opendlg.Filter = "Xml files (*.xml)|*.xml";
            if ((bool)opendlg.ShowDialog())
            {
                Mouse.OverrideCursor = Cursors.Wait;
                MergeKeys(Code.XmlHandler.ImportMsdnXml(new Uri(opendlg.FileName)));
            }
            SetView();
            Mouse.OverrideCursor = Cursors.Arrow;
        }

        protected void MenuHelpAboutClicked(object sender, RoutedEventArgs e)
        {
            AboutDialog helpWin = new AboutDialog();
            helpWin.Owner = this;
            helpWin.ShowDialog();
        }

        protected void ToolsPurgeDbClicked(object sender, RoutedEventArgs e)
        {
            try
            {
                if (BSCTaskDialog.BSCTaskDialog.TaskDialog(this, "Purge Databse?", "Are you sure you want to the contents of the PKM database?",
                    "This will remote all Products and all Keys permanently", TaskDialogButtons.Yes | TaskDialogButtons.No,
                    TaskDialogIcon.Warning) == TaskDialogResult.Yes)
                {
                    db.Products.DeleteAllOnSubmit(products);
                    db.SubmitChanges();
                    SetView();
                }
            }
            catch (Exception ex)
            {
                if (MessageBox.Show("Are you sure you want to the contents of the PKM database?", "Purge Databse?", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
                {
                    db.Products.DeleteAllOnSubmit(products);
                    db.SubmitChanges();
                    SetView();
                }
            }
            db.Products.DeleteAllOnSubmit(products);
            db.SubmitChanges();
            SetView();
        }

        protected void SearchKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == System.Windows.Input.Key.Return)
            {
                chkSearch.IsChecked = !chkSearch.IsChecked;
                if ((bool)chkSearch.IsChecked)
                {
                    OnSearch(sender, null);
                }
                else
                {
                    OnUnSearch(sender, null);
                }
            }
            if (e.Key == System.Windows.Input.Key.Escape)
            {
                if ((bool)chkSearch.IsChecked)
                {
                    chkSearch.IsChecked = false;
                    OnUnSearch(sender, null);
                }
            }
        }

        protected void ListBoxKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == System.Windows.Input.Key.Delete)
            {
                DeleteButtonClicked(sender, (RoutedEventArgs)e);
            }
        }

        void listProdKeys_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            bool isSelected = false;
            if(listProdKeys.SelectedIndex > -1)
            {
                isSelected = true;
            }

            menuEdit.IsEnabled = isSelected;
            toolbEdit.IsEnabled = isSelected;
        }

        protected void listProdKeys_DoubleClicked(object sender, RoutedEventArgs e)
        {
            if (listProdKeys.SelectedIndex > -1)
            {
                ViewKey viewWindow = new ViewKey();
                viewWindow.DataContext = listProdKeys.SelectedItem;
                viewWindow.Owner = this;
                viewWindow.ShowDialog();
            }
        }

        protected void FileMenuExportMsdnPkmClicked(object sender, RoutedEventArgs e)
        {
            string xml = Code.XmlHandler.ExportPkmXml(products);
            SaveFileDialog save = new SaveFileDialog();
            save.DefaultExt = "xml";
            save.Filter = "Xml files (*.xml)|*.xml";
            if ((bool)save.ShowDialog())
            {
                Mouse.OverrideCursor = Cursors.Wait;
                File.WriteAllText(save.FileName, xml, Encoding.Default);
            }
            Mouse.OverrideCursor = Cursors.Arrow;
        }

        protected void FileMenuExportMsdnXmlClicked(object sender, RoutedEventArgs e)
        {
            string xml = Code.XmlHandler.ExportMsdnXml(products);
            SaveFileDialog save = new SaveFileDialog();
            save.DefaultExt = "xml";
            save.Filter = "Xml files (*.xml)|*.xml";
            if ((bool)save.ShowDialog())
            {
                Mouse.OverrideCursor = Cursors.Wait;
                File.WriteAllText(save.FileName, xml, Encoding.Default);
            }
            Mouse.OverrideCursor = Cursors.Arrow;
        }

        protected void FileImportExportClicked(object sender, RoutedEventArgs e)
        {
            ImportExportWizard wiz = new ImportExportWizard();
            wiz.Navigate(new Uri("ImportExport1.xaml", UriKind.Relative));
            wiz.ShowDialog();
        }
    }
}